#include <linux/mmzone.h>
#include <linux/list.h>
#include <linux/init.h>
#include <linux/nodemask.h>

#define for_each_migratetype_order(order, type)      \
    for (order = 0; order < NR_PAGE_ORDERS; order++) \
        for (type = 0; type < MIGRATE_TYPES; type++)

static void zone_init_free_lists(struct zone *zone)
{
    unsigned int order, t;

    for_each_migratetype_order(order, t)
    {
        INIT_LIST_HEAD(&zone->free_area[order].free_list[t]);
        zone->free_area[order].nr_free = 0;
    }
}

void init_currently_empty_zone(struct zone *zone,
                               unsigned long zone_start_pfn,
                               unsigned long size)
{
    zone->zone_start_pfn = zone_start_pfn;

    zone_init_free_lists(zone);
}

static inline int zref_in_nodemask(struct zoneref *zref, nodemask_t *nodes)
{
#ifdef CONFIG_NUMA
    return node_isset(zonelist_node_idx(zref), *nodes);
#else
    return 1;
#endif /* CONFIG_NUMA */
}

/* Returns the next zone at or below highest_zoneidx in a zonelist */
struct zoneref *__next_zones_zonelist(struct zoneref *z,
                                      enum zone_type highest_zoneidx,
                                      nodemask_t *nodes)
{
    /*
     * Find the next suitable zone to use for the allocation.
     * Only filter based on nodemask if it's set
     */
    if (unlikely(nodes == NULL))
        while (zonelist_zone_idx(z) > highest_zoneidx)
            z++;
    else
        while (zonelist_zone_idx(z) > highest_zoneidx ||
               (zonelist_zone(z) && !zref_in_nodemask(z, nodes)))
            z++;

    return z;
}

static inline void zoneref_set_zone(struct zone *zone, struct zoneref *zoneref)
{
    zoneref->zone = zone;
    zoneref->zone_idx = zone_idx(zone);
}

/*
 * Builds allocation fallback zone lists.
 *
 * Add all populated zones of a node to the zonelist.
 */
static int build_zonerefs_node(pg_data_t *pgdat, struct zoneref *zonerefs)
{
    struct zone *zone;
    enum zone_type zone_type = MAX_NR_ZONES;
    int nr_zones = 0;

    do
    {
        zone_type--;
        zone = pgdat->node_zones + zone_type;
        if (populated_zone(zone))
        {
            zoneref_set_zone(zone, &zonerefs[nr_zones++]);
        }
    } while (zone_type);

    return nr_zones;
}

static void build_zonelists(pg_data_t *pgdat)
{
	struct zoneref *zonerefs;
	int nr_zones;

	zonerefs = pgdat->node_zonelists[ZONELIST_FALLBACK]._zonerefs;
	nr_zones = build_zonerefs_node(pgdat, zonerefs);
	zonerefs += nr_zones;

    zonerefs->zone = NULL;
    zonerefs->zone_idx = 0;
}

static void __build_all_zonelists(pg_data_t *self)
{
    int nid;

    if (self)
    {
    }
    else
    {
        /*
         * All possible nodes have pgdat preallocated
         * in free_area_init
         */
        for_each_node(nid)
        {
            pg_data_t *pgdat = NODE_DATA(nid);

            build_zonelists(pgdat);
        }
    }
}

void __init build_all_zonelists_init(void)
{
    __build_all_zonelists(NULL);
}

/*
 * unless system_state == SYSTEM_BOOTING.
 *
 * __ref due to call of __init annotated helper build_all_zonelists_init
 * [protected by SYSTEM_BOOTING].
 */
void build_all_zonelists(pg_data_t *pgdat)
{
}
